﻿using System.Collections.ObjectModel;

namespace Mitosoft.Definitions.ViewModels
{
  /// <summary>
  /// Represents the view model of a tree view item supporting lazy loading.
  /// </summary>
  public class TreeViewItemViewModel : BaseViewModel, ITreeViewItemViewModel
  {
    #region fields

    /// <summary>
    /// Dummy used to identify whether loading childrens is needed.
    /// </summary>
    private static readonly ITreeViewItemViewModel _dummyChild = new TreeViewItemViewModel();

    /// <summary>
    /// Represents the children.
    /// </summary>
    private ObservableCollection<ITreeViewItemViewModel> _children;

    /// <summary>
    /// Represents the parent item of this tree view item.
    /// Should be null for the root item.
    /// </summary>
    private readonly ITreeViewItemViewModel _parent;

    /// <summary>
    /// Represents <see cref="IsExpanded"/>
    /// </summary>
    private bool _isExpanded;

    /// <summary>
    /// Represents <see cref="IsSelected"/>
    /// </summary>
    private bool _isSelected;

    #endregion

    #region constructors

    /// <summary>
    /// Creates a new <see cref="TreeViewItemViewModel"/> instance.
    /// </summary>
    /// <param name="parent"></param>
    /// <param name="lazyLoadChildren"></param>
    protected TreeViewItemViewModel(ITreeViewItemViewModel parent, bool lazyLoadChildren)
    {
      _parent = parent;
        
      Children = new ObservableCollection<ITreeViewItemViewModel>();

      if (lazyLoadChildren)
        Children.Add(_dummyChild);
    }

    /// <summary>
    /// Creates a new <see cref="TreeViewItemViewModel"/> instance.
    /// </summary>
    /// <remarks>Used to create the DummyChild instance.</remarks>
    private TreeViewItemViewModel()
    {
      // Intentionally left blank.
    }

    #endregion

    #region properties

    /// <summary>
    /// Returns the logical child items of this object.
    /// </summary>
    public ObservableCollection<ITreeViewItemViewModel> Children
    {
      get
      {
        return _children;
      }
      protected set
      {
        if (_children == value)
          return;

        _children = value;
        HandlePropertyChanged();
      }
    }

    /// <summary>
    /// Returns true if this object's Children have not yet been populated.
    /// </summary>
    protected bool HasDummyChild
    {
      get
      {
        if (Children == null) return false;
        return Children.Count == 1 && Children[0] == _dummyChild;
      }
    }

    /// <summary>
    /// Gets/sets whether the TreeViewItem 
    /// associated with this object is expanded.
    /// </summary>
    public bool IsExpanded
    {
      get { return _isExpanded; }
      set
      {
        if (value != _isExpanded)
        {
          _isExpanded = value;
          HandlePropertyChanged();
        }

        // Expand all the way up to the root.
        if (_isExpanded && _parent != null)
          _parent.IsExpanded = true;

        // Lazy load the child items, if necessary.
        if (HasDummyChild)
        {
          Children.Remove(_dummyChild);
          LoadChildren();
        }
      }
    }

    /// <summary>
    /// Gets/sets whether the TreeViewItem 
    /// associated with this object is selected.
    /// </summary>
    public bool IsSelected
    {
      get { return _isSelected; }
      set
      {
        if (value == _isSelected) 
          return;
        
        _isSelected = value;
        HandlePropertyChanged();
      }
    }

    /// <summary>
    /// Gets the parent of this item.
    /// </summary>
    public ITreeViewItemViewModel Parent
    {
      get { return _parent; }
    }

    /// <summary>
    /// Gets the text which should be displayed.
    /// </summary>
    public virtual string DisplayText
    {
      get
      {
        return ToString();
      }
    }

    #endregion

    #region methods

    /// <summary>
    /// Invoked when the child items need to be loaded on demand.
    /// Subclasses should override this to populate the Children collection.
    /// Only needed if the subclasses owns logically children.
    /// </summary>
    protected virtual void LoadChildren()
    {
    }

    #endregion
  }
}
